home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2001 May / may_2001.iso / intercd / root / Multimedia / ^DivX_Article / virtualdub / VirtualDub-source-1_4d / AsyncBlitter.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-03-20  |  24.5 KB  |  1,077 lines

  1. //    VirtualDub - Video processing and capture application
  2. //    Copyright (C) 1998-2001 Avery Lee
  3. //
  4. //    This program is free software; you can redistribute it and/or modify
  5. //    it under the terms of the GNU General Public License as published by
  6. //    the Free Software Foundation; either version 2 of the License, or
  7. //    (at your option) any later version.
  8. //
  9. //    This program is distributed in the hope that it will be useful,
  10. //    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. //    GNU General Public License for more details.
  13. //
  14. //    You should have received a copy of the GNU General Public License
  15. //    along with this program; if not, write to the Free Software
  16. //    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  
  18. #include <process.h>
  19. #include <crtdbg.h>
  20.  
  21. #include <ddraw.h>
  22.  
  23. #include "AsyncBlitter.h"
  24. #include "Error.h"
  25. #include "cpuaccel.h"
  26. #include "tls.h"
  27.  
  28. #include "VBitmap.h"
  29. #include "ddrawsup.h"
  30.  
  31. #define USE_DRAWDIBDRAW
  32. //#define USE_STRETCHDIBITS
  33. //#define USE_SETDIBITSTODEVICE
  34.  
  35.  
  36. #ifdef _DEBUG
  37. #define LOCK_SET(x)        (lock_state |= (x))
  38. #define LOCK_CLEAR(x)    (lock_state &= ~(x))
  39. #define LOCK_RESET        (lock_state = LOCK_NONE)
  40. #else
  41. #define LOCK_SET(x)
  42. #define LOCK_CLEAR(x)
  43. #define LOCK_RESET
  44. #endif
  45.  
  46. AsyncBlitter::AsyncBlitter() {
  47.     max_requests        = 0;
  48.     requests            = NULL;
  49.     dwLockedBuffers        = NULL;
  50.     fAbort                = FALSE;
  51.     fFlush                = false;
  52.     fPulsed                = FALSE;
  53.     pulseCallback        = NULL;
  54.  
  55.     hEventDraw            = INVALID_HANDLE_VALUE;
  56.     hEventDrawReturn    = INVALID_HANDLE_VALUE;
  57.     hEventAbort            = INVALID_HANDLE_VALUE;
  58.     hThreadDraw            = NULL;
  59.  
  60.     LOCK_RESET;
  61.  
  62.     if (INVALID_HANDLE_VALUE == (hEventDraw = CreateEvent(NULL,FALSE,FALSE,NULL)))
  63.         throw MyError("Couldn't create draw event");
  64. }
  65.  
  66. AsyncBlitter::AsyncBlitter(int maxreq) {
  67.  
  68.     max_requests        = maxreq;
  69.     requests            = new AsyncBlitRequest[max_requests];
  70.     memset(requests,0,sizeof(AsyncBlitRequest)*max_requests);
  71.     dwLockedBuffers        = NULL;
  72.     fAbort                = FALSE;
  73.     fFlush                = false;
  74.     fPulsed                = FALSE;
  75.     pulseCallback        = NULL;
  76.  
  77.     hEventDraw            = INVALID_HANDLE_VALUE;
  78.     hEventDrawReturn    = INVALID_HANDLE_VALUE;
  79.     hEventAbort            = INVALID_HANDLE_VALUE;
  80.     hThreadDraw            = NULL;
  81.  
  82.     LOCK_RESET;
  83.  
  84.     if (INVALID_HANDLE_VALUE == (hEventDraw = CreateEvent(NULL,FALSE,FALSE,NULL)))
  85.         throw MyError("Couldn't create draw event");
  86.  
  87.     if (INVALID_HANDLE_VALUE == (hEventDrawReturn = CreateEvent(NULL,FALSE,FALSE,NULL)))
  88.         throw MyError("Couldn't create draw return event");
  89.  
  90.     if (INVALID_HANDLE_VALUE == (hEventAbort = CreateEvent(NULL,FALSE,FALSE,NULL)))
  91.         throw MyError("Couldn't create abort event");
  92.  
  93.     if (!(hThreadDraw = (HANDLE)_beginthread(drawThread, 10000, (void *)this)))
  94.         throw MyError("Couldn't create draw thread!");
  95.  
  96.     SetThreadPriority(hThreadDraw, THREAD_PRIORITY_HIGHEST);
  97. }
  98.  
  99. AsyncBlitter::~AsyncBlitter() {
  100.     if (hThreadDraw) {
  101.         fAbort = TRUE;
  102.  
  103.         while(hThreadDraw) {
  104.             SetEvent(hEventDraw);
  105.  
  106.             LOCK_SET(LOCK_DESTROY);
  107.             WaitForSingleObject(hEventAbort, INFINITE);
  108.             LOCK_CLEAR(LOCK_DESTROY);
  109.         }
  110.     }
  111.  
  112.     if (hEventDraw)            CloseHandle(hEventDraw);
  113.     if (hEventDrawReturn)    CloseHandle(hEventDrawReturn);
  114.     if (hEventAbort)        CloseHandle(hEventAbort);
  115.  
  116.     delete requests;
  117. }
  118.  
  119.  
  120.  
  121. ///////////////////////////////////////////
  122.  
  123.  
  124.  
  125. void AsyncBlitter::enablePulsing(BOOL p) {
  126.     dwPulseFrame = 0;
  127.     dwDrawFrame = 0;
  128.     fPulsed = p;
  129. }
  130.  
  131. void AsyncBlitter::pulse() {
  132.     ++dwPulseFrame;
  133.     SetEvent(hEventDraw);
  134. }
  135.  
  136. void AsyncBlitter::setPulseClock(DWORD clk) {
  137.     if (clk <= dwPulseFrame)
  138.         return;
  139.  
  140.     dwPulseFrame = clk;
  141.     SetEvent(hEventDraw);
  142. }
  143.  
  144. void AsyncBlitter::lock(DWORD id) {
  145.     if (!requests || fAbort) return;
  146.  
  147.     if (dwLockedBuffers & id) {
  148.         while((dwLockedBuffers & id) && !fAbort) {
  149.             LOCK_SET(LOCK_LOCK);
  150.             WaitForSingleObject(hEventDrawReturn, INFINITE);
  151.             LOCK_CLEAR(LOCK_LOCK);
  152.         }
  153.     }
  154.     dwLockedBuffers |= id;
  155. }
  156.  
  157. void AsyncBlitter::unlock(DWORD id) {
  158.     if (!requests) return;
  159.  
  160.     dwLockedBuffers &= ~id;
  161. }
  162.  
  163. void AsyncBlitter::setPulseCallback(BOOL (*pc)(void *, DWORD), void *pcd) {
  164.     pulseCallback = pc;
  165.     pulseCallbackData = pcd;
  166. }
  167.  
  168. BOOL AsyncBlitter::waitPulse(DWORD framenum) {
  169.     if (fPulsed) {
  170.         int pcret = PCR_OKAY;
  171.  
  172.         do {
  173.             if (pulseCallback) {
  174.                 pcret = pulseCallback(pulseCallbackData, framenum);
  175.                 if (pcret == PCR_WAIT) {
  176.                     LOCK_SET(LOCK_PULSE);
  177.                     WaitForSingleObject(hEventDraw, INFINITE);
  178.                     LOCK_CLEAR(LOCK_PULSE);
  179.                 }
  180.             } else
  181.                 while(!fAbort && !fFlush && (signed long)(dwPulseFrame-framenum) < 0) {
  182.                     LOCK_SET(LOCK_PULSE);
  183.                     WaitForSingleObject(hEventDraw, INFINITE);
  184.                     LOCK_CLEAR(LOCK_PULSE);
  185.                 }
  186.         } while(pcret == PCR_WAIT && !fAbort && !fFlush);
  187.  
  188.         if (pcret == PCR_NOBLIT) return FALSE;
  189.     }
  190.  
  191.     return fAbort;
  192. }
  193.  
  194. void AsyncBlitter::nextFrame(long adv) {
  195.     dwDrawFrame += adv;
  196. }
  197.  
  198. long AsyncBlitter::getFrameDelta() {
  199.     return dwPulseFrame - dwDrawFrame;
  200. }
  201.  
  202. void AsyncBlitter::postDirectDrawCopy(DWORD id, void *data, BITMAPINFOHEADER *pbih, IDDrawSurface *pDest) {
  203.     int i;
  204.  
  205.     if (fAbort) {
  206.         unlock(id);
  207.         return;
  208.     }
  209.  
  210.     if (!requests) {
  211.         VBitmap vbm;
  212.  
  213.         if (pDest->Lock(&vbm)) {
  214.             int h = vbm.h;
  215.             int w = vbm.w;
  216.             unsigned char *dst = (unsigned char *)vbm.data;
  217.             unsigned char *src = (unsigned char *)data;
  218.             long lBytes;
  219.  
  220.             lBytes = (w*pbih->biBitCount)/8;
  221.  
  222.             do {
  223.                 memcpy(dst, src, lBytes);
  224.  
  225.                 src += lBytes;
  226.                 dst += vbm.pitch;
  227.             } while(--h);
  228.  
  229.             pDest->Unlock();
  230.         }
  231.         unlock(id);
  232.         return;
  233.     }
  234.  
  235.     for(;;) {
  236.         for(i=0; i<max_requests; i++)
  237.             if (!requests[i].bufferID) break;
  238.  
  239.         if (i < max_requests) break;
  240.  
  241.         LOCK_SET(LOCK_POST);
  242.         WaitForSingleObject(hEventDrawReturn, INFINITE);
  243.         LOCK_CLEAR(LOCK_POST);
  244.  
  245.         if (fAbort) {
  246.             unlock(id);
  247.             return;
  248.         }
  249.     }
  250.  
  251.     requests[i].type        = AsyncBlitRequest::REQTYPE_DIRECTDRAWCOPY;
  252.  
  253.     requests[i].ddcopy.data    = data;
  254.     requests[i].ddcopy.pbih = pbih;
  255.     requests[i].ddcopy.pDest = pDest;
  256.  
  257.     requests[i].framenum    = dwDrawFrame;
  258.     requests[i].bufferID    = id;        // must be last!!!!
  259.  
  260.     SetEvent(hEventDraw);    
  261. }
  262.  
  263. void AsyncBlitter::postDirectDrawCopyLaced(DWORD id, void *data, BITMAPINFOHEADER *pbih, IDDrawSurface *pDest, bool bFieldBDominant) {
  264.     int i;
  265.  
  266.     if (fAbort) {
  267.         unlock(id);
  268.         return;
  269.     }
  270.  
  271.     if (!requests) {
  272.         VBitmap vbm;
  273.  
  274.         if (pDest->Lock(&vbm)) {
  275.             int h = vbm.h;
  276.             int w = vbm.w;
  277.             unsigned char *dst = (unsigned char *)vbm.data;
  278.             unsigned char *src = (unsigned char *)data;
  279.             long lBytes;
  280.  
  281.             lBytes = (w*pbih->biBitCount)/8;
  282.  
  283.             do {
  284.                 memcpy(dst, src, lBytes);
  285.  
  286.                 src += lBytes;
  287.                 dst += vbm.pitch;
  288.             } while(--h);
  289.  
  290.             pDest->Unlock();
  291.         }
  292.         unlock(id);
  293.         return;
  294.     }
  295.  
  296.     for(;;) {
  297.         for(i=0; i<max_requests; i++)
  298.             if (!requests[i].bufferID) break;
  299.  
  300.         if (i < max_requests) break;
  301.  
  302.         LOCK_SET(LOCK_POST);
  303.         WaitForSingleObject(hEventDrawReturn, INFINITE);
  304.         LOCK_CLEAR(LOCK_POST);
  305.  
  306.         if (fAbort) {
  307.             unlock(id);
  308.             return;
  309.         }
  310.     }
  311.  
  312.     requests[i].type        = AsyncBlitRequest::REQTYPE_DIRECTDRAWCOPYLACED;
  313.  
  314.     requests[i].ddcopy.data    = data;
  315.     requests[i].ddcopy.pbih = pbih;
  316.     requests[i].ddcopy.pDest = pDest;
  317.     requests[i].ddcopy.bFirst = true;
  318.     requests[i].ddcopy.bFieldBDominant = bFieldBDominant;
  319.  
  320.     requests[i].framenum    = dwDrawFrame;
  321.     requests[i].bufferID    = id;        // must be last!!!!
  322.  
  323.     SetEvent(hEventDraw);    
  324. }
  325.  
  326. void AsyncBlitter::postDirectDrawBlit(DWORD id, IDirectDrawSurface *pDst, IDDrawSurface *pSrc, int xDst, int yDst, int dxDst, int dyDst) {
  327.     int i;
  328.  
  329.     if (fAbort) {
  330.         unlock(id);
  331.         return;
  332.     }
  333.  
  334.     if (!requests) return;
  335.  
  336.     for(;;) {
  337.         for(i=0; i<max_requests; i++)
  338.             if (!requests[i].bufferID) break;
  339.  
  340.         if (i < max_requests) break;
  341.  
  342.         LOCK_SET(LOCK_POST);
  343.         WaitForSingleObject(hEventDrawReturn, INFINITE);
  344.         LOCK_CLEAR(LOCK_POST);
  345.  
  346.         if (fAbort) {
  347.             unlock(id);
  348.             return;
  349.         }
  350.     }
  351.  
  352.     requests[i].type        = AsyncBlitRequest::REQTYPE_DIRECTDRAWBLIT;
  353.  
  354.     requests[i].ddblit.pSrc        = pSrc;
  355.     requests[i].ddblit.pDest    = pDst;
  356.     requests[i].ddblit.r.left    = xDst;
  357.     requests[i].ddblit.r.top    = yDst;
  358.     requests[i].ddblit.r.right    = xDst + dxDst;
  359.     requests[i].ddblit.r.bottom    = yDst + dyDst;
  360.  
  361.     requests[i].framenum    = dwDrawFrame;
  362.     requests[i].bufferID    = id;        // must be last!!!!
  363.  
  364.     SetEvent(hEventDraw);    
  365. }
  366.  
  367. void AsyncBlitter::postDirectDrawBlitLaced(DWORD id, IDirectDrawSurface *pDst, IDDrawSurface *pSrc, int xDst, int yDst, int dxDst, int dyDst, bool bFieldBDominant) {
  368.     int i;
  369.  
  370.     if (fAbort) {
  371.         unlock(id);
  372.         return;
  373.     }
  374.  
  375.     if (!requests) return;
  376.  
  377.     for(;;) {
  378.         for(i=0; i<max_requests; i++)
  379.             if (!requests[i].bufferID) break;
  380.  
  381.         if (i < max_requests) break;
  382.  
  383.         LOCK_SET(LOCK_POST);
  384.         WaitForSingleObject(hEventDrawReturn, INFINITE);
  385.         LOCK_CLEAR(LOCK_POST);
  386.  
  387.         if (fAbort) {
  388.             unlock(id);
  389.             return;
  390.         }
  391.     }
  392.  
  393.     requests[i].type        = AsyncBlitRequest::REQTYPE_DIRECTDRAWBLITLACED;
  394.  
  395.     requests[i].ddblit.pSrc        = pSrc;
  396.     requests[i].ddblit.pDest    = pDst;
  397.     requests[i].ddblit.r.left    = xDst;
  398.     requests[i].ddblit.r.top    = yDst;
  399.     requests[i].ddblit.r.right    = xDst + dxDst;
  400.     requests[i].ddblit.r.bottom    = yDst + dyDst;
  401.     requests[i].ddblit.bFieldBDominant    = bFieldBDominant;
  402.     requests[i].ddblit.bFirst    = true;
  403.  
  404.     requests[i].framenum    = dwDrawFrame;
  405.     requests[i].bufferID    = id;        // must be last!!!!
  406.  
  407.     SetEvent(hEventDraw);    
  408. }
  409.  
  410. void AsyncBlitter::post(DWORD id, HDRAWDIB hdd, HDC hdc, int xDst, int yDst, int dxDst, int dyDst, LPBITMAPINFOHEADER lpbi,
  411.               LPVOID lpBits, int xSrc, int ySrc, int dxSrc, int dySrc, UINT wFlags) {
  412.  
  413.     int i;
  414.  
  415.     if (fAbort) {
  416.         unlock(id);
  417.         return;
  418.     }
  419.  
  420.     if (!requests) {
  421.         if (!waitPulse(dwDrawFrame))
  422.             DrawDibDraw(hdd, hdc, xDst, yDst, dxDst, dyDst, lpbi, lpBits, xSrc, ySrc, dxSrc, dySrc, wFlags);
  423.  
  424.         return;
  425.     }
  426.  
  427.     for(;;) {
  428.         for(i=0; i<max_requests; i++)
  429.             if (!requests[i].bufferID) break;
  430.  
  431.         if (i < max_requests) break;
  432.  
  433.         LOCK_SET(LOCK_POST);
  434.         WaitForSingleObject(hEventDrawReturn, INFINITE);
  435.         LOCK_CLEAR(LOCK_POST);
  436.  
  437.         if (fAbort) {
  438.             unlock(id);
  439.             return;
  440.         }
  441.     }
  442.  
  443.     requests[i].type                = AsyncBlitRequest::REQTYPE_DRAWDIB;
  444.     requests[i].drawdib.hdd            = hdd;
  445.     requests[i].drawdib.hdc            = hdc;
  446.     requests[i].drawdib.xDst        = xDst;
  447.     requests[i].drawdib.yDst        = yDst;
  448.     requests[i].drawdib.dxDst        = dxDst;
  449.     requests[i].drawdib.dyDst        = dyDst;
  450.     requests[i].drawdib.lpbi        = lpbi;
  451.     requests[i].drawdib.lpBits        = lpBits;
  452.     requests[i].drawdib.xSrc        = xSrc;
  453.     requests[i].drawdib.ySrc        = ySrc;
  454.     requests[i].drawdib.dxSrc        = dxSrc;
  455.     requests[i].drawdib.dySrc        = dySrc;
  456.     requests[i].drawdib.wFlags        = wFlags;
  457.  
  458.     requests[i].framenum    = dwDrawFrame;
  459.     requests[i].bufferID    = id;        // must be last!!!!
  460.  
  461.     SetEvent(hEventDraw);
  462. }
  463.  
  464. void AsyncBlitter::postStretchBlt(DWORD id, HDC hdcDst, int xDst, int yDst, int dxDst, int dyDst,
  465.             HDC hdcSrc, int xSrc, int ySrc, int dxSrc, int dySrc) {
  466.  
  467.     int i;
  468.  
  469.     if (fAbort) {
  470.         unlock(id);
  471.         return;
  472.     }
  473.  
  474.     if (!requests) {
  475.         if (!waitPulse(dwDrawFrame))
  476.             if (dxDst == dxSrc && dyDst == dySrc)
  477.                 BitBlt(hdcDst, xDst, yDst, dxDst, dyDst, hdcSrc, xSrc, ySrc, SRCCOPY);
  478.             else
  479.                 StretchBlt(hdcDst, xDst, yDst, dxDst, dyDst, hdcSrc, xSrc, ySrc, dxSrc, dySrc, SRCCOPY);
  480.  
  481.         return;
  482.     }
  483.  
  484.     for(;;) {
  485.         for(i=0; i<max_requests; i++)
  486.             if (!requests[i].bufferID) break;
  487.  
  488.         if (i < max_requests) break;
  489.  
  490.         LOCK_SET(LOCK_POST);
  491.         WaitForSingleObject(hEventDrawReturn, INFINITE);
  492.         LOCK_CLEAR(LOCK_POST);
  493.  
  494.         if (fAbort) {
  495.             unlock(id);
  496.             return;
  497.         }
  498.     }
  499.  
  500.     requests[i].type                = AsyncBlitRequest::REQTYPE_STRETCHBLT;
  501.     requests[i].stretchblt.hdcDst    = hdcDst;
  502.     requests[i].stretchblt.xDst        = xDst;
  503.     requests[i].stretchblt.yDst        = yDst;
  504.     requests[i].stretchblt.dxDst    = dxDst;
  505.     requests[i].stretchblt.dyDst    = dyDst;
  506.     requests[i].stretchblt.hdcSrc    = hdcSrc;
  507.     requests[i].stretchblt.xSrc        = xSrc;
  508.     requests[i].stretchblt.ySrc        = ySrc;
  509.     requests[i].stretchblt.dxSrc    = dxSrc;
  510.     requests[i].stretchblt.dySrc    = dySrc;
  511.  
  512.     requests[i].framenum    = dwDrawFrame;
  513.     requests[i].bufferID    = id;        // must be last!!!!
  514.  
  515.     SetEvent(hEventDraw);
  516. }
  517.  
  518. void AsyncBlitter::postBitBltLaced(DWORD id, HDC hdcDst, int xDst, int yDst, int dxDst, int dyDst,
  519.             HDC hdcSrc, int xSrc, int ySrc, bool bFieldBDominant) {
  520.  
  521.     int i;
  522.  
  523.     if (fAbort) {
  524.         unlock(id);
  525.         return;
  526.     }
  527.  
  528.     if (!requests) {
  529.         if (!waitPulse(dwDrawFrame))
  530.             BitBlt(hdcDst, xDst, yDst, dxDst, dyDst, hdcSrc, xSrc, ySrc, SRCCOPY);
  531.  
  532.         return;
  533.     }
  534.  
  535.     for(;;) {
  536.         for(i=0; i<max_requests; i++)
  537.             if (!requests[i].bufferID) break;
  538.  
  539.         if (i < max_requests) break;
  540.  
  541.         LOCK_SET(LOCK_POST);
  542.         WaitForSingleObject(hEventDrawReturn, INFINITE);
  543.         LOCK_CLEAR(LOCK_POST);
  544.  
  545.         if (fAbort) {
  546.             unlock(id);
  547.             return;
  548.         }
  549.     }
  550.  
  551.     requests[i].type                = AsyncBlitRequest::REQTYPE_BITBLTLACED;
  552.     requests[i].stretchblt.hdcDst    = hdcDst;
  553.     requests[i].stretchblt.xDst        = xDst;
  554.     requests[i].stretchblt.yDst        = yDst;
  555.     requests[i].stretchblt.dxDst    = dxDst;
  556.     requests[i].stretchblt.dyDst    = dyDst;
  557.     requests[i].stretchblt.hdcSrc    = hdcSrc;
  558.     requests[i].stretchblt.xSrc        = xSrc;
  559.     requests[i].stretchblt.ySrc        = ySrc;
  560.     requests[i].stretchblt.dxSrc    = bFieldBDominant ? 1 : 0;
  561.     requests[i].stretchblt.dySrc    = 0;
  562.  
  563.     requests[i].framenum    = dwDrawFrame;
  564.     requests[i].bufferID    = id;        // must be last!!!!
  565.  
  566.     SetEvent(hEventDraw);
  567. }
  568.  
  569. void AsyncBlitter::postStretchDIBits(DWORD id, HDC hdc, int xDst, int yDst, int dxDst, int dyDst, int xSrc, int ySrc, int dxSrc, int dySrc, const void *pBits, const BITMAPINFO *pBitsInfo, UINT iUsage, DWORD dwRop) {
  570.     int i;
  571.  
  572.     if (fAbort) {
  573.         unlock(id);
  574.         return;
  575.     }
  576.  
  577.     if (!requests) {
  578.         if (!waitPulse(dwDrawFrame))
  579.             StretchDIBits(hdc, xDst, yDst, dxDst, dyDst, xSrc, ySrc, dxSrc, dySrc, pBits, pBitsInfo, iUsage, dwRop);
  580.  
  581.         return;
  582.     }
  583.  
  584.     for(;;) {
  585.         for(i=0; i<max_requests; i++)
  586.             if (!requests[i].bufferID) break;
  587.  
  588.         if (i < max_requests) break;
  589.  
  590.         LOCK_SET(LOCK_POST);
  591.         WaitForSingleObject(hEventDrawReturn, INFINITE);
  592.         LOCK_CLEAR(LOCK_POST);
  593.  
  594.         if (fAbort) {
  595.             unlock(id);
  596.             return;
  597.         }
  598.     }
  599.  
  600.     requests[i].type                    = AsyncBlitRequest::REQTYPE_STRETCHDIBITS;
  601.     requests[i].stretchdibits.hdc        = hdc;
  602.     requests[i].stretchdibits.xDst        = xDst;
  603.     requests[i].stretchdibits.yDst        = yDst;
  604.     requests[i].stretchdibits.dxDst        = dxDst;
  605.     requests[i].stretchdibits.dyDst        = dyDst;
  606.     requests[i].stretchdibits.xSrc        = xSrc;
  607.     requests[i].stretchdibits.ySrc        = ySrc;
  608.     requests[i].stretchdibits.dxSrc        = dxSrc;
  609.     requests[i].stretchdibits.dySrc        = dySrc;
  610.     requests[i].stretchdibits.pBits        = pBits;
  611.     requests[i].stretchdibits.pBitsInfo    = pBitsInfo;
  612.     requests[i].stretchdibits.iUsage    = iUsage;
  613.     requests[i].stretchdibits.dwRop        = dwRop;
  614.  
  615.     requests[i].framenum    = dwDrawFrame;
  616.     requests[i].bufferID    = id;        // must be last!!!!
  617.  
  618.     SetEvent(hEventDraw);
  619. }
  620.  
  621. void AsyncBlitter::postICDraw(DWORD id, HIC hic, DWORD dwFlags, LPVOID pFormat, LPVOID pData, DWORD cbData, LONG lTime) {
  622.     int i;
  623.  
  624.     if (fAbort) {
  625.         unlock(id);
  626.         return;
  627.     }
  628.  
  629.     if (!requests) {
  630.         ICDraw(hic, dwFlags, pFormat, pData, cbData, lTime);
  631.         return;
  632.     }
  633.  
  634.     for(;;) {
  635.         for(i=0; i<max_requests; i++)
  636.             if (!requests[i].bufferID) break;
  637.  
  638.         if (i < max_requests) break;
  639.  
  640.         LOCK_SET(LOCK_POST);
  641.         WaitForSingleObject(hEventDrawReturn, INFINITE);
  642.         LOCK_CLEAR(LOCK_POST);
  643.  
  644.         if (fAbort) {
  645.             unlock(id);
  646.             return;
  647.         }
  648.     }
  649.  
  650.     requests[i].type            = AsyncBlitRequest::REQTYPE_ICDRAW;
  651.  
  652.     requests[i].icdraw.hic        = hic;
  653.     requests[i].icdraw.dwFlags    = dwFlags;
  654.     requests[i].icdraw.pFormat    = pFormat;
  655.     requests[i].icdraw.pData    = pData;
  656.     requests[i].icdraw.cbData    = cbData;
  657.     requests[i].icdraw.lTime    = lTime;
  658.  
  659.     requests[i].framenum    = dwDrawFrame;
  660.     requests[i].bufferID    = id;        // must be last!!!!
  661.  
  662.     SetEvent(hEventDraw);    
  663. }
  664.  
  665. void AsyncBlitter::postAFC(DWORD id, void (*pFunc)(void *), void *pData) {
  666.     int i;
  667.  
  668.     if (fAbort) {
  669.         return;
  670.     }
  671.  
  672.     lock(id);
  673.  
  674.     if (!requests) {
  675.         pFunc(pData);
  676.         return;
  677.     }
  678.  
  679.     for(;;) {
  680.         for(i=0; i<max_requests; i++)
  681.             if (!requests[i].bufferID) break;
  682.  
  683.         if (i < max_requests) break;
  684.  
  685.         LOCK_SET(LOCK_POST);
  686.         WaitForSingleObject(hEventDrawReturn, INFINITE);
  687.         LOCK_CLEAR(LOCK_POST);
  688.  
  689.         if (fAbort) {
  690.             unlock(id);
  691.             return;
  692.         }
  693.     }
  694.  
  695.     requests[i].type            = AsyncBlitRequest::REQTYPE_AFC;
  696.  
  697.     requests[i].afc.pFunc        = pFunc;
  698.     requests[i].afc.pData        = pData;
  699.  
  700.     requests[i].bufferID    = id;        // must be last!!!!
  701.  
  702.     SetEvent(hEventDraw);
  703.  
  704.     // wait for request to complete
  705.  
  706.     lock(id);
  707.     unlock(id);
  708. }
  709.  
  710. void AsyncBlitter::release(DWORD id) {
  711.     if (!requests) return;
  712.  
  713.     dwLockedBuffers &= ~id;
  714.     SetEvent(hEventDrawReturn);
  715. }
  716.  
  717. void AsyncBlitter::abort() {
  718.     fAbort = TRUE;
  719. }
  720.  
  721. void AsyncBlitter::flush() {
  722.     if (!requests)
  723.         return;
  724.  
  725.     fFlush = true;
  726.     SetEvent(hEventDraw);
  727.  
  728.     while(fFlush)
  729.         WaitForSingleObject(hEventAbort, INFINITE);
  730. }
  731.  
  732. void AsyncBlitter::drawThread(void *param) {
  733.     InitThreadData("AsyncBlitter");
  734.     ((AsyncBlitter *)param)->drawThread2();
  735.     DeinitThreadData();
  736. }
  737.  
  738. static void __declspec(naked) MMXcopy(void *dst, void *src, int cnt) {
  739.     __asm {
  740.         mov    ecx,[esp+4]
  741.         mov    edx,[esp+8]
  742.         mov eax,[esp+12]
  743. copyloop:
  744.         movq    mm0,[edx]
  745.         movq    [ecx],mm0
  746.         add        edx,8
  747.         add        ecx,8
  748.         dec        eax
  749.         jne        copyloop
  750.         ret
  751.     };
  752. }
  753.  
  754. static void __declspec(naked) move_to_vidmem(void *dst, void *src, long dstpitch, long srcpitch, int w, int h) {
  755.     __asm {
  756.         push    ebp
  757.         push    edi
  758.         push    esi
  759.         push    ebx
  760.  
  761.         mov        ebx,[esp+8+16]
  762.         mov        edx,[esp+4+16]
  763.         mov        eax,[esp+20+16]
  764.         mov        ebp,[esp+24+16]
  765.         mov        esi,eax
  766.         and        eax,0ffffffe0h
  767.         neg        eax
  768.         mov        [esp+20+16],eax
  769.         and        esi,31
  770.         mov        [esp+4+16],esi
  771.         sub        ebx,eax
  772.         sub        edx,eax
  773.  
  774. yloop:
  775.         mov        eax,[esp+20+16]
  776. xloop:
  777.         fild    qword ptr [ebx+eax]        ;0
  778.         fild    qword ptr [ebx+eax+8]    ;1 0
  779.         fild    qword ptr [ebx+eax+16]    ;2 1 0
  780.         fild    qword ptr [ebx+eax+24]    ;3 2 1 0
  781.         fxch    st(3)                    ;0 2 1 3
  782.         fistp    qword ptr [edx+eax]        ;2 1 3
  783.         fistp    qword ptr [edx+eax+16]    ;1 3
  784.         fistp    qword ptr [edx+eax+8]    ;3
  785.         fistp    qword ptr [edx+eax+24]
  786.         add        eax,32
  787.         jnz        xloop
  788.  
  789.         mov        ecx,[esp+4+16]
  790.         mov        esi,ebx
  791.         mov        edi,edx
  792.         rep        movsb
  793.  
  794.         add        ebx,[esp+16+16]
  795.         add        edx,[esp+12+16]
  796.  
  797.         dec        ebp
  798.         jne        yloop
  799.  
  800.         pop        ebx
  801.         pop        esi
  802.         pop        edi
  803.         pop        ebp
  804.         ret
  805.     }
  806. }
  807.  
  808. bool AsyncBlitter::DoRequest(AsyncBlitRequest *req) {
  809.     // DrawDibDraw(), StretchDIBits(), and SetDIBitsToDevice() are about the same...
  810.  
  811.     switch(req->type) {
  812.     case AsyncBlitRequest::REQTYPE_DRAWDIB:
  813.  
  814.         DrawDibDraw(req->drawdib.hdd, req->drawdib.hdc, req->drawdib.xDst, req->drawdib.yDst, req->drawdib.dxDst, req->drawdib.dyDst,
  815.             req->drawdib.lpbi, req->drawdib.lpBits, req->drawdib.xSrc, req->drawdib.ySrc, req->drawdib.dxSrc, req->drawdib.dySrc, req->drawdib.wFlags);
  816.  
  817.         GdiFlush();
  818.         break;
  819.  
  820.     case AsyncBlitRequest::REQTYPE_BITBLTLACED:
  821.         {
  822.             // It's actually four times faster to do 240 bitblts than to blit through
  823.             // an interlaced clip region.
  824.  
  825.             for(int y=req->stretchblt.dxSrc; y<req->stretchblt.dyDst; y+=2) {
  826.                 BitBlt(req->stretchblt.hdcDst, req->stretchblt.xDst, req->stretchblt.yDst+y, req->stretchblt.dxDst, 1,
  827.                         req->stretchblt.hdcSrc, req->stretchblt.xSrc, req->stretchblt.ySrc+y, SRCCOPY);
  828.             }
  829.  
  830.             GdiFlush();
  831.  
  832.             req->stretchblt.dxSrc ^= 1;
  833.             return ++req->stretchblt.dySrc<2;
  834.         }
  835.         break;
  836.  
  837.     case AsyncBlitRequest::REQTYPE_STRETCHBLT:
  838.  
  839.         // BitBlt/StretchBlt request
  840.  
  841.         if (req->stretchblt.dxDst == req->stretchblt.dxSrc && req->stretchblt.dyDst == req->stretchblt.dySrc)
  842.             BitBlt(req->stretchblt.hdcDst, req->stretchblt.xDst, req->stretchblt.yDst, req->stretchblt.dxDst, req->stretchblt.dyDst,
  843.                     req->stretchblt.hdcSrc, req->stretchblt.xSrc, req->stretchblt.ySrc, SRCCOPY);
  844.         else
  845.             StretchBlt(req->stretchblt.hdcDst, req->stretchblt.xDst, req->stretchblt.yDst, req->stretchblt.dxDst, req->stretchblt.dyDst,
  846.                     req->stretchblt.hdcSrc, req->stretchblt.xSrc, req->stretchblt.ySrc, req->stretchblt.dxSrc, req->stretchblt.dySrc, SRCCOPY);
  847.  
  848.         GdiFlush();
  849.         break;
  850.  
  851.     case AsyncBlitRequest::REQTYPE_STRETCHDIBITS:
  852.         StretchDIBits(
  853.             req->stretchdibits.hdc,
  854.             req->stretchdibits.xDst,
  855.             req->stretchdibits.yDst,
  856.             req->stretchdibits.dxDst,
  857.             req->stretchdibits.dyDst,
  858.             req->stretchdibits.xSrc,
  859.             req->stretchdibits.ySrc,
  860.             req->stretchdibits.dxSrc,
  861.             req->stretchdibits.dySrc,
  862.             req->stretchdibits.pBits,
  863.             req->stretchdibits.pBitsInfo,
  864.             req->stretchdibits.iUsage,
  865.             req->stretchdibits.dwRop);
  866.         GdiFlush();
  867.         break;
  868.  
  869.     case AsyncBlitRequest::REQTYPE_DIRECTDRAWCOPY:
  870.  
  871.         {
  872.             VBitmap vbm;
  873.  
  874.             if (req->ddcopy.pDest->Lock(&vbm)) {
  875.                 int h = vbm.h;
  876.                 int w = vbm.w;
  877.                 unsigned char *dst = (unsigned char *)vbm.data;
  878.                 unsigned char *src = (unsigned char *)req->ddcopy.data;
  879.                 long lBytes;
  880.  
  881. //                                dst += vbm.pitch*(h-1);
  882.  
  883.                 lBytes = (w*req->ddcopy.pbih->biBitCount)/8;
  884.  
  885. //                if (!MMX_enabled)
  886. //                    move_to_vidmem(dst, src, vbm.pitch, lBytes, lBytes, h);
  887. //                else
  888.                 if (MMX_enabled && !(((long)dst | (long)src)&7) && !(lBytes&7)) {
  889.                     do {
  890.                         MMXcopy(dst, src, lBytes/8);
  891.  
  892.                         src += lBytes;
  893.                         dst += vbm.pitch;
  894.                     } while(--h);
  895.                     __asm emms
  896.                 } else
  897.                     do {
  898.                         memcpy(dst, src, lBytes);
  899.  
  900.                         src += lBytes;
  901.                         dst += vbm.pitch;
  902.                     } while(--h);
  903.  
  904.                 req->ddcopy.pDest->Unlock();
  905.             }
  906.  
  907.         }
  908.  
  909.         break;
  910.  
  911.     case AsyncBlitRequest::REQTYPE_DIRECTDRAWCOPYLACED:
  912.  
  913.         {
  914.             VBitmap vbm;
  915.  
  916.             if (req->ddcopy.pDest->Lock(&vbm)) {
  917.                 int h = vbm.h;
  918.                 int w = vbm.w;
  919.                 unsigned char *dst = (unsigned char *)vbm.data;
  920.                 unsigned char *src = (unsigned char *)req->ddcopy.data;
  921.                 long lBytes;
  922.  
  923.                 lBytes = (w*req->ddcopy.pbih->biBitCount)/8;
  924.  
  925.                 if (!(req->ddcopy.bFirst ^ req->ddcopy.bFieldBDominant)) {
  926.                     src += lBytes;
  927.                     dst += vbm.pitch;
  928.                 }
  929.  
  930.                 h >>= 1;
  931.  
  932.                 if (MMX_enabled && !(((long)dst | (long)src)&7) && !(lBytes&7)) {
  933.                     do {
  934.                         MMXcopy(dst, src, lBytes/8);
  935.  
  936.                         src += lBytes*2;
  937.                         dst += vbm.pitch*2;
  938.                     } while(--h);
  939.                     __asm emms
  940.                 } else
  941.                     do {
  942.                         memcpy(dst, src, lBytes);
  943.  
  944.                         src += lBytes*2;
  945.                         dst += vbm.pitch*2;
  946.                     } while(--h);
  947.  
  948.                 req->ddcopy.pDest->Unlock();
  949.             }
  950.  
  951.             return !(req->ddcopy.bFirst = !req->ddcopy.bFirst);
  952.         }
  953.  
  954.         break;
  955.  
  956.     case AsyncBlitRequest::REQTYPE_DIRECTDRAWBLIT:
  957.         req->ddblit.pDest->Blt(&req->ddblit.r, req->ddblit.pSrc->getSurface(), NULL, DDBLT_WAIT, NULL);
  958.  
  959.         break;
  960.  
  961.     case AsyncBlitRequest::REQTYPE_DIRECTDRAWBLITLACED:
  962.         {
  963.             int y = req->ddblit.bFieldBDominant?1:0;
  964.             int h = req->ddblit.r.bottom - req->ddblit.r.top;
  965.             RECT rSrc;
  966.             int xo = req->ddblit.r.left;
  967.             int yo = req->ddblit.r.top;
  968.             IDirectDrawSurface *pDDS = req->ddblit.pSrc->getSurface();
  969.             IDirectDrawSurface3 *pDDS3;
  970.             bool bPageLocked = false;
  971.  
  972.             rSrc.left = 0;
  973.             rSrc.right = req->ddblit.r.right - req->ddblit.r.left;
  974.  
  975.             if (SUCCEEDED(pDDS->QueryInterface(IID_IDirectDrawSurface3, (void **)&pDDS3))) {
  976.                 if (SUCCEEDED(pDDS3->PageLock(0)))
  977.                     bPageLocked = true;
  978.             } else
  979.                 pDDS3 = NULL;
  980.  
  981.             for(; y<h; y+=2) {
  982.                 rSrc.top    = y;
  983.                 rSrc.bottom    = y+1;
  984.  
  985.                 req->ddblit.pDest->BltFast(xo, yo+y, pDDS, &rSrc,
  986.                     DDBLTFAST_WAIT|DDBLTFAST_NOCOLORKEY);
  987.             }
  988.  
  989.             if (bPageLocked) {
  990.                 pDDS3->PageUnlock(0);
  991.             }
  992.  
  993.             if (pDDS3)
  994.                 pDDS3->Release();
  995.  
  996.             req->ddblit.bFieldBDominant = !req->ddblit.bFieldBDominant;
  997.         }
  998.         return !(req->ddblit.bFirst = !req->ddblit.bFirst);
  999.  
  1000.     case AsyncBlitRequest::REQTYPE_ICDRAW:
  1001.         ICDraw(req->icdraw.hic, req->icdraw.dwFlags, req->icdraw.pFormat, req->icdraw.pData, req->icdraw.cbData, req->icdraw.lTime);
  1002.         break;
  1003.  
  1004.     case AsyncBlitRequest::REQTYPE_AFC:
  1005.         req->afc.pFunc(req->afc.pData);
  1006.         break;
  1007.     }
  1008.  
  1009.     return false;
  1010. }
  1011.  
  1012. bool AsyncBlitter::ServiceRequests(bool fWait) {
  1013.     AsyncBlitRequest *req;
  1014.     bool fRequestServiced = false;
  1015.     int i;
  1016.  
  1017.     if (fFlush) {
  1018.         req = requests;
  1019.  
  1020.         for(i=0; i<max_requests; ++i,++req) {
  1021.             if (req->bufferID) {
  1022.                 release(req->bufferID);
  1023.                 req->bufferID = 0;
  1024.             }
  1025.         }
  1026.  
  1027.         fFlush = false;
  1028.         SetEvent(hEventAbort);
  1029.  
  1030.         return true;
  1031.     }
  1032.  
  1033.     req = requests;
  1034.  
  1035.     for(i=0; i<max_requests && !fAbort; ++i,++req) {
  1036.         if (req->bufferID) {
  1037.             fRequestServiced = true;
  1038.  
  1039.             if (req->type == AsyncBlitRequest::REQTYPE_AFC)
  1040.                 DoRequest(req);
  1041.             else if (!fWait || !waitPulse(req->framenum)) {
  1042.                 if (dwPulseFrame < req->framenum)
  1043.                     continue;
  1044.  
  1045.                 if (DoRequest(req)) {
  1046.                     ++req->framenum;
  1047.                     continue;
  1048.                 }
  1049.             }
  1050.  
  1051.             release(req->bufferID);
  1052.             req->bufferID = 0;
  1053.         }
  1054.     }
  1055.  
  1056.     return fRequestServiced;
  1057. }
  1058.  
  1059. void AsyncBlitter::drawThread2() {
  1060.     _RPT0(0,"AsyncBlitter: Thread started.\n");
  1061.  
  1062.     while(!fAbort) {
  1063.         if (!ServiceRequests(true) && !fAbort) {
  1064.             LOCK_SET(LOCK_ASYNC_EXIT);
  1065.             WaitForSingleObject(hEventDraw, INFINITE);
  1066.             LOCK_CLEAR(LOCK_ASYNC_EXIT);
  1067.         }
  1068.     }
  1069.  
  1070.     dwLockedBuffers = 0;
  1071.     hThreadDraw = 0;
  1072.     SetEvent(hEventDraw);
  1073.     SetEvent(hEventAbort);
  1074.  
  1075.     _RPT0(0,"AsyncBlitter: thread exit.\n");
  1076. }
  1077.